package excelrept

import (
	"bytes"
	"database/sql"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/huandu/go-clone"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
	"shqsoft.cn/pas3ui/base"
)

//CellDatas 单元格数据
type CellDatas struct {
	TableName string            `json:"tableName"`
	CellData  map[string]string `json:"cellData"`
}

//SaveSheetData 按照sheet保存cellsData
func SaveSheetData(reptName string, params map[string]string, cellDatas []CellDatas) (err error) {
	var workPath string
	if workPath, err = base.WorkDir(); err != nil {
		err = fmt.Errorf("获取执行路径出错！%s", err)
		return
	}
	filePath := workPath + "/template/" + reptName + ".xlsx"
	xlsx, err := NewXlsxHelper(filePath)
	if err != nil {
		return
	}
	conf, err := getConfig(reptName)
	if err != nil {
		return err
	}
	offSet := 0
	prevSheet := ""
	for _, cData := range cellDatas {
		var tConf *Table
		for _, t := range conf.Tables {
			if strings.EqualFold(t.Name, cData.TableName) {
				tConf = &t
				break
			}
		}
		if tConf == nil {
			return fmt.Errorf("在报表%s的配置中没有找到表%s", reptName, cData.TableName)
		}
		if prevSheet != tConf.Sheet {
			offSet = 0
		}
		_, err = saveData(reptName, tConf, params, xlsx, cData, offSet)
		if err != nil {
			return err
		}
		tx := base.CHDB.Begin()
		offSet, err = importTable(tConf, xlsx, params, offSet, tx)
		if err != nil {
			tx.Rollback()
			return err
		}
		tx.Commit()
		prevSheet = tConf.Sheet
	}
	return nil
}
func saveData(reptName string, tConf *Table, params map[string]string, xlsx *XlsxHelper, cData CellDatas, startOffset int) (endOffset int, err error) {
	dbCols, err := getDBColumns(tConf.Name)
	if err != nil {
		return 0, err
	}
	err = UpdateChuShi(reptName, params)
	if err != nil {
		return 0, err
	}
	var col, row int
	var colName string
	var ok bool
	var cVal interface{}
	var cName string
	cellVals := make(map[string]interface{}, 10)
	xlsx.file.WorkBook.CalcPr.ForceFullCalc = true
	_, _, _, erow, err := parseRange(tConf.DataRange)
	if err != nil {
		return 0, err
	}
	maxRow := erow
	var axis string
	var convF ConvertFunc
	for k, v := range cData.CellData {
		if isUnused(tConf, k) {
			continue
		}
		convF = nil
		col, row, err = parseAxis(k)
		if err != nil {
			return
		}
		if len(tConf.Columns) > 0 {
			cName, err = excelize.ColumnNumberToName(col)
			if err != nil {
				return
			}
			colName, ok = tConf.Columns[cName]
			if !ok {
				continue
			}
			if colName == tConf.RowNoCol {
				continue
			}
			for _, dbCol := range dbCols {
				if strings.EqualFold(dbCol.Name, colName) {
					convF = dbCol.convertFunc
					break
				}
			}
			if convF == nil {
				return 0, fmt.Errorf("表%s中没有找到字段%s", tConf.Name, colName)
			}
		} else {
			for _, dbCol := range dbCols {
				if strings.EqualFold(dbCol.Name, tConf.Cells[k]) {
					convF = dbCol.convertFunc
					break
				}
			}
			if convF == nil {
				continue
			}
		}
		fm, err := xlsx.file.GetCellFormula(tConf.Sheet, k)
		if err != nil {
			return 0, err
		}
		if fm != "" {
			continue
		}
		cVal, err = convF(v)
		if err != nil {
			return 0, err
		}
		if tval, ok := cVal.(time.Time); ok {
			cVal = tval.Format("2006-01-02")
		}
		if row >= erow {
			cellVals[k] = cVal
			if maxRow < row {
				maxRow = row
			}
		} else {
			axis = k
			if startOffset > 0 {
				axis = cName + strconv.Itoa(row+startOffset)
			}
			xlsx.file.SetCellValue(tConf.Sheet, axis, cVal)
		}
	}
	erow2 := erow
	fms := make(map[string]string, 10)
	for ; erow2 < maxRow; erow2++ {
		if tConf.FormulaDerive.Rows != nil {
			for _, axis := range tConf.FormulaDerive.Rows {
				col, row, err := parseAxis(axis)
				if err != nil {
					return 0, err
				}
				fm, err := xlsx.file.GetCellFormula(tConf.Sheet, axis)
				if err != nil {
					return 0, err
				}
				fm = strings.ReplaceAll(fm, strconv.Itoa(row), strconv.Itoa(erow2))
				cName, err := excelize.ColumnNumberToName(col)
				if err != nil {
					return 0, err
				}
				naxis := cName + strconv.Itoa(erow2)
				fms[naxis] = fm
			}
		}
		xlsx.file.InsertRows(tConf.Sheet, erow2, 1)
	}
	for k, v := range cellVals {
		xlsx.file.SetCellValue(tConf.Sheet, k, v)
	}
	ignoreFms := make([]string, 0, 10)
	if tConf.FormulaDerive.Cells != nil {
		for _, axis := range tConf.FormulaDerive.Cells {
			col, row, err := parseAxis(axis)
			if err != nil {
				return 0, err
			}
			cName, err := excelize.ColumnNumberToName(col)
			if err != nil {
				return 0, err
			}
			naxis := cName + strconv.Itoa(maxRow)
			fm, err := xlsx.file.GetCellFormula(tConf.Sheet, naxis)
			if err != nil {
				return 0, err
			}
			fm = strings.ReplaceAll(fm, strconv.Itoa(row-1), strconv.Itoa(maxRow-1))
			if err != nil {
				return 0, err
			}
			fms[naxis] = fm
			ignoreFms = append(ignoreFms, axis)
		}
	}
	fc, err := NewFormulaCalc(reptName, tConf, cData.CellData)
	if err != nil {
		return 0, err
	}
	fcVals, err := fc.CalcFormulas(ignoreFms...)
	if err != nil {
		return 0, err
	}
	for axis, fm := range fms {
		fcVals[axis], err = fc.calcFormula(fm, ignoreFms...)
		if err != nil {
			return 0, err
		}
	}
	for k, v := range fcVals {
		xlsx.file.SetCellValue(tConf.Sheet, k, v)
	}
	endOffset = maxRow - erow
	return
}

//保存时如果是归口就更新初始化
func UpdateChuShi(reptName string, params map[string]string) (err error) {
	var rpid int
	tx := base.CHDB.Begin()
	sqlStr := `select RPID from T_CONF_REPORTS WHERE RPNO=?`
	row := tx.Raw(sqlStr, reptName).Row()
	row.Scan(&rpid)
	var isgk bool
	tbjg, err := strconv.Atoi(params["TBJG"])
	if err != nil {
		return err
	}
	if tbjg == 0 || tbjg == 1 || tbjg == 2 {
		isgk = true
	}
	if isgk {
		if tbjg == 1 || tbjg == 2 {
			var updStr string
			updStr = "update T_REPT_FLOW set FHCSH=1 where RPID=? and TBSJ=?"
			if params["TBJG"] == "2" {
				updStr = "update T_REPT_FLOW set ZMCSH=1 where RPID=? and TBSJ=?"
			}
			err = tx.Exec(updStr, rpid, params["TBSJ"]).Error
			if err != nil {
				tx.Rollback()
				return err
			}
			tx.Commit()
		}
	}
	return
}

//GetPageData 获取生成页面所需数据
func GetPageData(reptName string, params map[string]string, rInfo *ReptInfo) (data *Template, err error) {
	tpl, err := GetTemplate(reptName)
	if err != nil {
		return nil, err
	}
	data = clone.Clone(tpl).(*Template)
	conf, err := getConfig(reptName)
	if err != nil {
		return nil, err
	}
	tlen := len(conf.Tables)
	if tlen == 0 {
		return nil, fmt.Errorf("报表%s没有配置tables", reptName)
	}
	offset := 0
	prevSheet := ""
	for _, t := range conf.Tables {
		tItem := data.getTableItem(t.Name)
		if tItem == nil {
			return nil, fmt.Errorf("表名%s没有找到", t.Name)
		}
		if t.Sheet != prevSheet {
			offset = 0
		}
		offset, err = fillTableData(&t, params, tItem, offset)
		if err != nil {
			return
		}
		prevSheet = t.Sheet
		_, _, _, endRow, err := parseRange(t.DataRange)
		if err != nil {
			return nil, err
		}
		if offset > 0 {
			mcs := make(map[string]MergeCell)
			index := -1
			for i := 0; i < len(data.Sheets); i++ {
				if data.Sheets[i].SheetName == t.Sheet {
					index = i
					for k, v := range data.Sheets[i].MergeCells {
						col, row, err := parseAxis(k)
						if err != nil {
							return nil, err
						}
						if row < endRow {
							mcs[k] = v
						} else {
							colStr, err := excelize.ColumnNumberToName(col)
							if err != nil {
								return nil, err
							}
							nk := colStr + strconv.Itoa(row+offset)
							scol, ecol, srow, erow, err := parseRange(v.Range)
							if err != nil {
								return nil, err
							}
							if srow > endRow {
								srow += offset
							}
							if erow > endRow {
								erow += offset
							}
							cols, err := excelize.ColumnNumberToName(scol)
							if err != nil {
								return nil, err
							}
							cole, err := excelize.ColumnNumberToName(ecol)
							if err != nil {
								return nil, err
							}
							v.Range = cols + strconv.Itoa(srow) + ":" + cole + strconv.Itoa(erow)
							mcs[nk] = v
						}
					}
					break
				}
			}
			data.Sheets[index].MergeCells = mcs
		}
	}
	if rInfo != nil {
		err = fillCells(reptName, conf, data, rInfo)
		if err != nil {
			return
		}
	}
	return
}

//InitRept 初始化报表
func InitReport(reptName string, params map[string]string) (err error) {
	conf, err := getConfig(reptName)
	if err != nil {
		return err
	}
	tx := base.CHDB.Begin()
	for _, t := range conf.Tables {
		err = delTable(&t, params, tx)
		if err != nil {
			tx.Rollback()
			return err
		}
	}
	tx.Commit()
	return
}

//InitRept 归并报表
func InitRept(reptName string, params map[string]string) (err error) {
	conf, err := getConfig(reptName)
	if err != nil {
		return err
	}
	var rpid int
	tx := base.CHDB.Begin()
	sqlStr := `select RPID from T_CONF_REPORTS WHERE RPNO=?`
	row := tx.Raw(sqlStr, reptName).Row()
	row.Scan(&rpid)
	sqlStr = "select FHCSH,ZMCSH,FRID from T_REPT_FLOW where RPID=? and TBSJ=?"
	var fhcsh, zmcsh bool
	var frid int
	row = tx.Raw(sqlStr, rpid, params["TBSJ"]).Row()
	err = row.Scan(&fhcsh, &zmcsh, &frid)
	if err != nil {
		return err
	}
	utids := make([]int, 0, 5)
	var isgk bool
	tbjg, err := strconv.Atoi(params["TBJG"])
	if err != nil {
		return err
	}
	if tbjg == 0 {
		isgk = true
	}
	if isgk {
		sqlStr := `select distinct B.UTID,B.STATE
			from T_FLOW_RUN_STEP b
								  inner join T_FLOW_RUN C ON B.RUNID=C.ID
			WHERE B.RUNID=?  AND b.STEPID=1`
		var utid int
		var state string
		rows, err := tx.Raw(sqlStr, frid).Rows()
		if err != nil {
			tx.Rollback()
			return err
		}
		defer rows.Close()
		for rows.Next() {
			rows.Scan(&utid, &state)
			if state == "0" || state == "1" {
				err = errors.New("业务部门还没有提交完成")
				tx.Rollback()
				return err
			}
			utids = append(utids, utid)
		}
	}
	for _, t := range conf.Tables {
		err = delTable(&t, params, tx)
		if err != nil {
			tx.Rollback()
			return err
		}
		if isgk && !t.IsList {
			tbsj := strings.ReplaceAll(params["TBSJ"], "-", "")
			err = sumTable(&t, tbsj, tbjg, utids, tx)
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	tx.Commit()
	if base.IsInSliceForInt(conf.InitDept, tbjg) && conf.InitProc != "" {
		err = base.CHDB.Exec("EXEC "+conf.InitProc+" ?,?", params["TBSJ"], params["TBJG"]).Error
		if err != nil {
			tx.Rollback()
			return err
		}
		tx.Commit()
		return
	}
	return
}
func parseSumRuleRange(tConf *Table, rang string) (colNames []string, srowNo int, erowNo int, err error) {
	var scol, ecol, srow, erow int
	scol, ecol, srow, erow, err = parseRange(rang)
	if err != nil {
		return
	}
	colNames = make([]string, 0, len(tConf.Columns))
	var cn, colName string
	for i := scol; i <= ecol; i++ {
		cn, err = excelize.ColumnNumberToName(i)
		if err != nil {
			return
		}
		colName = tConf.Columns[cn]
		if colName == "" {
			err = fmt.Errorf("汇总规则配置错误，没有找列%s对应的字段", cn)
			return
		}
		colNames = append(colNames, colName)
	}
	if srow < tConf.RowStart {
		err = fmt.Errorf("汇总规则配置错误，行号%d不能小于表%s的数据开始行%d", srow, tConf.Name, tConf.RowStart)
	}
	srowNo = srow - tConf.RowStart + 1
	erowNo = erow - tConf.RowStart + 1
	return
}
func sumTable(tConf *Table, tbsj string, tbjg int, utids []int, tx *gorm.DB) (err error) {
	cols := make([]string, 0, len(tConf.Columns))
	for _, cName := range tConf.Columns {
		cols = append(cols, cName)
	}
	var sumSQLs []string
	if tConf.SumRules != nil && len(tConf.SumRules) > 0 {
		sumSQLs = make([]string, len(tConf.SumRules))
		for i, sRule := range tConf.SumRules {
			colNames, srowNo, erowNo, err := parseSumRuleRange(tConf, sRule.Range)
			if err != nil {
				return err
			}
			sumSQLs[i], err = sumSQLByRange(tConf, tbsj, tbjg, sRule.OrgIds, cols, colNames, srowNo, erowNo, tx)
			if err != nil {
				return err
			}
		}
	}
	var buff bytes.Buffer
	var buff2 bytes.Buffer
	var buff3 bytes.Buffer
	buff.WriteString("insert into ")
	buff.WriteString(tConf.Name)
	buff.WriteString("(TBSJ,TBJG,")
	buff.WriteString(tConf.RowNoCol)
	buff.WriteString(",")
	buff2.WriteString("select ?,?,")
	buff2.WriteString(tConf.RowNoCol)
	buff2.WriteString(",")
	buff3.WriteString("(select ")
	buff3.WriteString(tConf.RowNoCol)
	buff3.WriteString(",")
	for _, cName := range cols {
		if strings.EqualFold(cName, tConf.RowNoCol) {
			continue
		}
		buff.WriteString(cName)
		buff.WriteString(",")
		buff2.WriteString("sum(")
		buff2.WriteString("isnull(")
		buff2.WriteString(cName)
		buff2.WriteString(",0)),")
		buff3.WriteString(cName)
		buff3.WriteString(",")
	}
	buff.Truncate(buff.Len() - 1)
	buff.WriteString(") ")
	buff2.Truncate(buff2.Len() - 1)
	buff2.WriteString(" from ")
	buff3.WriteString("ROW_NUMBER() OVER(PARTITION BY TBJG ORDER BY ID) ROWNUM from ")
	buff3.WriteString(tConf.Name)
	if sumSQLs == nil {
		buff2.Write(buff3.Bytes())
		buff2.WriteString(" where ")
		buff2.WriteString("TBSJ=? AND TBJG in ")
		buff2.WriteString("(?)) T ")
	} else {
		buff2.WriteString(" (")
		for i, ss := range sumSQLs {
			buff2.WriteString(ss)
			if i < len(sumSQLs)-1 {
				buff2.WriteString(" union all ")
			}
		}
		buff2.WriteString(") t ")
	}
	buff2.WriteString("where ")
	buff2.WriteString(tConf.RowNoCol)
	buff2.WriteString(">0 ")
	buff2.WriteString("group by ")
	// if sumSQLs != nil {
	// 	buff2.WriteString("ROWNUM,")
	// }
	buff2.WriteString(tConf.RowNoCol)
	buff2.WriteString(" ORDER BY ")
	buff2.WriteString(tConf.RowNoCol)
	// if sumSQLs != nil {
	// 	buff2.WriteString("ROWNUM")
	// } else {
	// 	buff2.WriteString(tConf.RowNoCol)
	// }
	buff.Write(buff2.Bytes())
	sumSQL := buff.String()
	if sumSQLs == nil {
		return tx.Exec(sumSQL, tbsj, tbjg, tbsj, utids).Error
	}
	return tx.Exec(sumSQL, tbsj, tbjg).Error
}

func sumSQLByRange(tConf *Table, tbsj string, tbjg int, utids []int, cols, colNames []string, srowNo, erowNo int, tx *gorm.DB) (sumSQL string, err error) {
	//如果是分行本部合计，剔除自贸区
	if tbjg == 1 {
		index := -1
		for i, utid := range utids {
			if utid == 2 {
				index = i
			}
		}
		if index != -1 {
			utids = append(utids[:index], utids[index+1:]...)
		}
	}
	var buff2 bytes.Buffer
	buff2.WriteString("select ")
	buff2.WriteString(tConf.RowNoCol)
	buff2.WriteString(",")
	var isHas bool
	for _, cName := range cols {
		if strings.EqualFold(cName, tConf.RowNoCol) {
			continue
		}
		isHas = false
		for _, cn2 := range colNames {
			if cName == cn2 {
				isHas = true
			}
		}
		if isHas {
			buff2.WriteString("sum(")
			buff2.WriteString("isnull(")
			buff2.WriteString(cName)
			buff2.WriteString(",0)) ")
			buff2.WriteString(cName)
			buff2.WriteString(",")
		} else {
			buff2.WriteString("0 ")
			buff2.WriteString(cName)
			buff2.WriteString(",")
		}
	}
	buff2.Truncate(buff2.Len() - 1)
	buff2.WriteString(" from ")
	buff2.WriteString(tConf.Name)
	buff2.WriteString(" where ")
	buff2.WriteString("TBSJ='")
	buff2.WriteString(tbsj)
	buff2.WriteString("' and TBJG in ")
	buff2.WriteString("(")
	for k, utid := range utids {
		buff2.WriteString(strconv.Itoa(utid))
		if k < len(utids)-1 {
			buff2.WriteString(",")
		}
	}
	buff2.WriteString(") and ")
	buff2.WriteString(tConf.RowNoCol)
	buff2.WriteString(">=")
	buff2.WriteString(strconv.Itoa(srowNo))
	buff2.WriteString(" and ")
	buff2.WriteString(tConf.RowNoCol)
	buff2.WriteString("<=")
	buff2.WriteString(strconv.Itoa(erowNo))
	buff2.WriteString(" group by ")
	buff2.WriteString(tConf.RowNoCol)
	sumSQL = buff2.String()
	return
}

func fillTableData(tConf *Table, params map[string]string, tItem *TableItem, startOffset int) (endOffset int, err error) {
	var buff bytes.Buffer
	buff.WriteString("select ")
	plen := len(params)
	vals := make([]interface{}, plen)
	dbCols, err := getDBColumns(tConf.Name)
	if err != nil {
		return 0, err
	}
	for i, col := range dbCols {
		if strings.HasPrefix(col.DataType, "Decimal") {
			buff.WriteString("toFloat64(")
			buff.WriteString(col.Name)
			buff.WriteString(") AS ")
			buff.WriteString(col.Name)
		} else {
			buff.WriteString(col.Name)
		}
		if i < len(dbCols)-1 {
			buff.WriteString(",")
		}
	}
	buff.WriteString(" from ")
	buff.WriteString(tConf.Name)
	if plen > 0 {
		buff.WriteString(" where ")
		var convF ConvertFunc
		i := 0
		for k, v := range params {
			convF = nil
			for _, col := range dbCols {
				if strings.EqualFold(col.Name, k) {
					convF = col.convertFunc
					break
				}
			}
			if convF == nil {
				return 0, fmt.Errorf("参数名%s在表%s中没有定义的字段", k, tConf.Name)
			}
			buff.WriteString(k)
			buff.WriteString("=?")
			if i < plen-1 {
				buff.WriteString(" and ")
			}
			vals[i], err = convF(v)
			if err != nil {
				return 0, err
			}
			i++
		}
		buff.WriteString(" and ")
		buff.WriteString(tConf.RowNoCol)
		buff.WriteString(">0")
	}
	buff.WriteString(" ORDER BY ")
	buff.WriteString(tConf.RowNoCol)
	srow := tItem.DataRange.SRow
	rows, err := base.CHDB.Raw(buff.String(), vals...).Rows()
	if err != nil {
		return 0, err
	}
	cols, err := base.GetColumns(rows)
	if err != nil {
		return 0, err
	}
	clen := len(cols)
	values := make([]sql.NullString, clen)
	scanArgs := make([]interface{}, clen)
	for i := 0; i < clen; i++ {
		scanArgs[i] = &values[i]
	}
	ri := 0
	var ucol string
	colConv := make(map[string]ConvertFunc)
	for _, col := range cols {
		ucol = strings.ToUpper(col)
		for _, dbcol := range dbCols {
			if ucol == strings.ToUpper(dbcol.Name) {
				colConv[ucol] = dbcol.convertFunc
				break
			}
		}
		if _, ok := colConv[ucol]; !ok {
			err = fmt.Errorf("配置错误，表%s不存在字段%s", tConf.Name, col)
		}
	}
	for rows.Next() {
		for i := 0; i < 5; i++ {
			if base.IsInSliceForInt(tConf.BlankRows, ri+srow) {
				blankVals := make([]sql.NullString, clen)
				if err := fillRow(tConf, cols, colConv, blankVals, ri+srow, tItem); err != nil {
					return 0, err
				}
				ri++
			} else {
				break
			}
		}
		err := rows.Scan(scanArgs...)
		if err != nil {
			return 0, err
		}
		if err := fillRow(tConf, cols, colConv, values, ri+srow, tItem); err != nil {
			return 0, err
		}
		ri++
	}
	rows.Close()
	// if ri
	if startOffset > 0 {
		tItem.DataRange.SRow += startOffset
		tItem.DataRange.ERow += startOffset
		if tItem.HeadRange.SRow > 0 {
			tItem.HeadRange.SRow += startOffset
			tItem.HeadRange.ERow += startOffset
		}
		if tItem.ColumnRange.SRow > 0 {
			tItem.ColumnRange.SRow += startOffset
			tItem.ColumnRange.ERow += startOffset
		}
		if tItem.RowRange.SRow > 0 {
			tItem.RowRange.SRow += startOffset
			tItem.RowRange.ERow += startOffset
		}
		dcells := make(map[string]string, len(tItem.DataCells))
		for k, v := range tItem.DataCells {
			col, row, err := parseAxis(k)
			if err != nil {
				return 0, err
			}
			cName, _ := excelize.ColumnNumberToName(col)
			nk := cName + strconv.Itoa(row+startOffset)
			dcells[nk] = v
		}
		tItem.DataCells = dcells
		hcells := make(map[string]string, len(tItem.HeadCells))
		for k, v := range tItem.HeadCells {
			col, row, err := parseAxis(k)
			if err != nil {
				return 0, err
			}
			cName, _ := excelize.ColumnNumberToName(col)
			nk := cName + strconv.Itoa(row+startOffset)
			hcells[nk] = v
		}
		tItem.HeadCells = hcells
		rowHs := make(map[int]float64, len(tItem.RowHeights))
		for k, v := range tItem.RowHeights {
			rowHs[k+startOffset] = v
		}
		tItem.RowHeights = rowHs
	}
	return
}
func fillCells(reptName string, conf *ReptConf, tpl *Template, rInfo *ReptInfo) (err error) {
	var cellVals map[string]string
	for sheetName := range conf.Cells {
		cellVals, err = getSpecialCellVals(reptName, sheetName, rInfo)
		if cellVals == nil {
			continue
		}
		for k, v := range cellVals {
			for i := 0; i < len(tpl.Sheets); i++ {
				if tpl.Sheets[i].SheetName == sheetName {
					if _, ok := tpl.Sheets[i].MergeCells[k]; ok {
						cval := tpl.Sheets[i].MergeCells[k]
						cval.Value = v
						tpl.Sheets[i].MergeCells[k] = cval
					}
				}
			}
			for _, t := range conf.Tables {
				if t.Sheet != sheetName {
					continue
				}
				tItem := tpl.getTableItem(t.Name)
				if tItem == nil {
					err = fmt.Errorf("表名%s没有找到", t.Name)
				}
				if _, ok := tItem.HeadCells[k]; ok {
					tItem.HeadCells[k] = v
				}
				if _, ok := tItem.HeadCells[k]; ok {
					tItem.HeadCells[k] = v
				} else if _, ok := tItem.TailCells[k]; ok {
					tItem.TailCells[k] = v
				} else if _, ok := tItem.ColumnCells[k]; ok {
					tItem.ColumnCells[k] = v
				} else if _, ok := tItem.DataCells[k]; ok {
					tItem.DataCells[k] = v
				}
			}
		}
	}
	return
}

func fillRow(tConf *Table, cols []string, colConv map[string]ConvertFunc, datas []sql.NullString, rowNo int, tItem *TableItem) (err error) {
	var index int
	var conv ConvertFunc
	var cellVal interface{}
	var curCol string
	colMap := tConf.Columns
	if len(colMap) == 0 {
		colMap = tConf.Cells
	}
	var axis string
	for k, v := range colMap {
		index = -1
		for i, col := range cols {
			if strings.EqualFold(col, v) {
				curCol = col
				conv = colConv[strings.ToUpper(col)]
				index = i
				break
			}
		}
		if index == -1 {
			err = fmt.Errorf("表%s中没有找到字段%s", tConf.Name, v)
			return
		}
		axis = k
		if len(tConf.Columns) > 0 {
			axis = k + strconv.Itoa(rowNo)
		}
		if isUnused(tConf, axis) {
			continue
		}
		if datas[index].Valid && datas[index].String != "" {
			if curCol == tConf.RowNoCol && datas[index].String == "999999" {
				cellVal = "合计"
			} else {
				cellVal, err = conv(datas[index].String)
				if err != nil {
					return
				}
				if tConf.Unit != 0 {
					if fval, ok := cellVal.(float64); ok {
						cellVal = fval / float64(tConf.Unit)
					}
				}
			}
			if tval, ok := cellVal.(time.Time); ok {
				cellVal = tval.Format("2006/01/02")
			}
			tItem.DataCells[axis] = toString(tConf, axis, cellVal)
		}
	}
	return
}
func toString(tConf *Table, axis string, val interface{}) string {
	var format string
	var isP bool
	for _, fm := range tConf.Formats {
		if inRange(fm.Range, axis) {
			format = fm.Format
			if format == "" {
				format = ".2f"
			} else {
				isP = strings.HasSuffix(format, "f%")
				if isP {
					format = format[0 : len(format)-1]
				}
			}
			f := "%" + format
			if isP {
				fval, ok := val.(float64)
				if ok {
					fval = fval * 100
					return fmt.Sprintf(f, fval) + "%"
				}
			}
			return fmt.Sprintf(f, val)
		}
	}
	return base.ToString(val)
}
